1 Summary

  1. Business Problem: AJ Operations would like to predict total hours to complete a trailer on a shift by shift basis
  2. Goal: Generate work content (Actual Hours) through predictive modeling leveraging 1yr of historical LM data.
  3. Independent variables that were considered in the models were: Std Time, Onstd Time, Cube, Cartons, Pallet, Lines, Cube per Hour, Cartons per hour, Pallet per hour and lines per hour.
  4. Receiving Operations can apply these models for estimating trailer completion times for offshore and domestic SKUs on a shift by shift basis by leveraging: cube, lines, pallets and cartons as lagging indicators for inputs into the model to determine staffing requirements

2 Load Receiving Data

3 Exploratory Time Series Analysis

3.1 Domestic SKUs Plot

3.2 Offshore SKUs

3.3 Correlation Matrix

3.3.1 Domestic Correlation matrix

3.3.2 Offshore Correlation matrix

4 Machine Learning

4.1 Data Preparation

4.1.1 Domestic Data

4.1.2 Offshore Data

4.2 Resample

4.2.1 Domestic Resample

## <Training/Testing/Total>
## <6972/1744/8716>
## Rows: 6,972
## Columns: 19
## $ rowid            <int> 2463, 2511, 2986, 1842, 3371, 4761, 6746, 2757, 5107,…
## $ STD_TIME         <dbl> 0.49, 0.14, 1.33, 0.37, 2.71, 1.32, 1.91, 0.52, 0.28,…
## $ ACTUAL_TIME      <dbl> 0.32, 0.12, 2.97, 0.03, 5.63, 3.05, 0.60, 1.38, 0.28,…
## $ INDIRECT_TIME    <dbl> 0.00, 0.00, 0.00, 0.00, 1.88, 0.00, 0.00, 0.20, 0.00,…
## $ ONSTD_TIME       <dbl> 0.32, 0.12, 2.48, 0.03, 4.60, 2.55, 0.60, 1.38, 0.28,…
## $ WEIGHT           <dbl> 436.00, 471.78, 3221.03, 1699.49, 13830.48, 4108.61, …
## $ CUBE             <dbl> 124.20, 50.27, 177.64, 56.27, 501.52, 576.33, 74.99, …
## $ CARTONS          <dbl> 80, 20, 443, 56, 752, 252, 78, 2100, 194, 449, 40, 63…
## $ PALLET           <dbl> 4, 1, 9, 1, 16, 9, 2, 5, 3, 7, 1, 6, 1, 1, 2, 3, 5, 1…
## $ LINES            <dbl> 1, 1, 2, 1, 2, 1, 1, 1, 1, 5, 1, 1, 1, 1, 1, 2, 1, 2,…
## $ EFF              <dbl> 153.12, 116.67, 53.63, 1233.33, 58.91, 51.76, 318.33,…
## $ WEIGHT_PH        <dbl> 1362.50, 3931.50, 1084.52, 56649.67, 2456.57, 1347.09…
## $ CUBE_PH          <dbl> 388.12, 418.92, 59.81, 1875.67, 89.08, 188.96, 124.98…
## $ CARTONS_PH       <dbl> 250.00, 166.67, 149.16, 1866.67, 133.57, 82.62, 130.0…
## $ PALLET_PH        <dbl> 12.50, 8.33, 3.03, 33.33, 2.84, 2.95, 3.33, 3.62, 10.…
## $ LINES_PH         <dbl> 3.12, 8.33, 0.67, 33.33, 0.36, 0.33, 1.67, 0.72, 3.57…
## $ TRAILER_PH       <dbl> 3.12, 8.33, 0.34, 33.33, 0.18, 0.33, 1.67, 0.72, 3.57…
## $ CUBE_PER_LINE    <dbl> 124.20, 50.27, 88.82, 56.27, 250.76, 576.33, 74.99, 2…
## $ CUBE_PER_TRAILER <dbl> 124.20, 50.27, 177.64, 56.27, 501.52, 576.33, 74.99, …

4.2.2 Offshore Resample

## <Training/Testing/Total>
## <13268/3318/16586>
## Rows: 13,268
## Columns: 19
## $ rowid            <int> 15455, 14662, 4003, 15140, 11705, 2230, 12663, 6531, …
## $ STD_TIME         <dbl> 3.72, 0.98, 0.29, 8.01, 8.76, 5.82, 0.62, 2.91, 1.74,…
## $ ACTUAL_TIME      <dbl> 4.98, 3.90, 0.62, 7.30, 18.02, 10.87, 1.12, 6.50, 2.4…
## $ INDIRECT_TIME    <dbl> 0.00, 2.50, 0.00, 0.77, 3.50, 0.00, 0.00, 0.00, 1.25,…
## $ ONSTD_TIME       <dbl> 4.65, 3.17, 0.62, 6.13, 15.35, 9.53, 0.77, 5.50, 2.15…
## $ WEIGHT           <dbl> 8043.49, 1236.00, 734.40, 5392.80, 20397.71, 10407.84…
## $ CUBE             <dbl> 531.56, 152.97, 52.42, 303.71, 1030.39, 672.29, 59.35…
## $ CARTONS          <dbl> 566.00, 145.00, 54.00, 840.00, 1858.00, 1574.00, 230.…
## $ PALLET           <dbl> 28, 5, 2, 5, 34, 40, 2, 17, 15, 46, 40, 29, 8, 10, 9,…
## $ LINES            <dbl> 23, 2, 1, 1, 11, 20, 2, 11, 12, 10, 20, 7, 1, 1, 4, 8…
## $ EFF              <dbl> 80.00, 30.91, 46.77, 130.67, 57.07, 61.07, 80.52, 52.…
## $ WEIGHT_PH        <dbl> 1615.16, 316.92, 1184.52, 738.74, 1131.95, 957.48, 79…
## $ CUBE_PH          <dbl> 106.74, 39.22, 84.55, 41.60, 57.18, 61.85, 52.99, 53.…
## $ CARTONS_PH       <dbl> 113.65, 37.18, 87.10, 115.07, 103.11, 144.80, 205.36,…
## $ PALLET_PH        <dbl> 5.62, 1.28, 3.23, 0.68, 1.89, 3.68, 1.79, 2.62, 6.05,…
## $ LINES_PH         <dbl> 4.62, 0.51, 1.61, 0.14, 0.61, 1.84, 1.79, 1.69, 4.84,…
## $ TRAILER_PH       <dbl> 0.20, 0.26, 1.61, 0.14, 0.06, 0.09, 0.89, 0.15, 0.40,…
## $ CUBE_PER_LINE    <dbl> 23.11, 76.48, 52.42, 303.71, 93.67, 33.61, 29.68, 31.…
## $ CUBE_PER_TRAILER <dbl> 531.56, 152.97, 52.42, 303.71, 1030.39, 672.29, 59.35…

4.3 Machine Learning Create Models

4.3.1 Domestic ML

4.3.1.1 Domestic Recipe

## Rows: 6,972
## Columns: 11
## $ STD_TIME    <dbl> 0.49, 0.14, 1.33, 0.37, 2.71, 1.32, 1.91, 0.52, 0.28, 1.12…
## $ ONSTD_TIME  <dbl> 0.32, 0.12, 2.48, 0.03, 4.60, 2.55, 0.60, 1.38, 0.28, 2.72…
## $ CUBE        <dbl> 124.20, 50.27, 177.64, 56.27, 501.52, 576.33, 74.99, 216.4…
## $ CARTONS     <dbl> 80, 20, 443, 56, 752, 252, 78, 2100, 194, 449, 40, 63, 3, …
## $ PALLET      <dbl> 4, 1, 9, 1, 16, 9, 2, 5, 3, 7, 1, 6, 1, 1, 2, 3, 5, 15, 3,…
## $ LINES       <dbl> 1, 1, 2, 1, 2, 1, 1, 1, 1, 5, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1…
## $ CUBE_PH     <dbl> 388.12, 418.92, 59.81, 1875.67, 89.08, 188.96, 124.98, 156…
## $ CARTONS_PH  <dbl> 250.00, 166.67, 149.16, 1866.67, 133.57, 82.62, 130.00, 15…
## $ PALLET_PH   <dbl> 12.50, 8.33, 3.03, 33.33, 2.84, 2.95, 3.33, 3.62, 10.71, 2…
## $ LINES_PH    <dbl> 3.12, 8.33, 0.67, 33.33, 0.36, 0.33, 1.67, 0.72, 3.57, 1.5…
## $ ACTUAL_TIME <dbl> 0.32, 0.12, 2.97, 0.03, 5.63, 3.05, 0.60, 1.38, 0.28, 3.22…

4.3.1.2 Domestic Workflow XGBoost Model

## ══ Workflow [trained] ══════════════════════════════════════════════════════════
## Preprocessor: Recipe
## Model: boost_tree()
## 
## ── Preprocessor ────────────────────────────────────────────────────────────────
## 0 Recipe Steps
## 
## ── Model ───────────────────────────────────────────────────────────────────────
## ##### xgb.Booster
## raw: 52.9 Kb 
## call:
##   xgboost::xgb.train(params = list(eta = 0.35, max_depth = 6, gamma = 0, 
##     colsample_bytree = 1, colsample_bynode = 1, min_child_weight = 1, 
##     subsample = 1), data = x$data, nrounds = 15, watchlist = x$watchlist, 
##     verbose = 0, nthread = 1, objective = "reg:squarederror")
## params (as set within xgb.train):
##   eta = "0.35", max_depth = "6", gamma = "0", colsample_bytree = "1", colsample_bynode = "1", min_child_weight = "1", subsample = "1", nthread = "1", objective = "reg:squarederror", validate_parameters = "TRUE"
## xgb.attributes:
##   niter
## callbacks:
##   cb.evaluation.log()
## # of features: 10 
## niter: 15
## nfeatures : 10 
## evaluation_log:
##     iter training_rmse
##        1     1.8078066
##        2     1.1960776
## ---                   
##       14     0.1109871
##       15     0.1079625

4.3.1.3 Domestic Workflow Linear Model

## ══ Workflow [trained] ══════════════════════════════════════════════════════════
## Preprocessor: Recipe
## Model: linear_reg()
## 
## ── Preprocessor ────────────────────────────────────────────────────────────────
## 0 Recipe Steps
## 
## ── Model ───────────────────────────────────────────────────────────────────────
## 
## Call:
## stats::lm(formula = ..y ~ ., data = data)
## 
## Coefficients:
## (Intercept)     STD_TIME   ONSTD_TIME         CUBE      CARTONS       PALLET  
##   3.253e-03    1.787e-03    1.152e+00    2.216e-05    1.376e-05   -9.395e-04  
##       LINES      CUBE_PH   CARTONS_PH    PALLET_PH     LINES_PH  
##   1.061e-03    2.354e-07   -2.000e-06   -2.593e-04   -1.114e-03

4.3.2 Offshore ML

4.3.2.1 Offshore Recipe

## Rows: 13,268
## Columns: 11
## $ STD_TIME    <dbl> 3.72, 0.98, 0.29, 8.01, 8.76, 5.82, 0.62, 2.91, 1.74, 7.75…
## $ ONSTD_TIME  <dbl> 4.65, 3.17, 0.62, 6.13, 15.35, 9.53, 0.77, 5.50, 2.15, 10.…
## $ CUBE        <dbl> 531.56, 152.97, 52.42, 303.71, 1030.39, 672.29, 59.35, 349…
## $ CARTONS     <dbl> 566.00, 145.00, 54.00, 840.00, 1858.00, 1574.00, 230.00, 3…
## $ PALLET      <dbl> 28, 5, 2, 5, 34, 40, 2, 17, 15, 46, 40, 29, 8, 10, 9, 34, …
## $ LINES       <dbl> 23, 2, 1, 1, 11, 20, 2, 11, 12, 10, 20, 7, 1, 1, 4, 8, 34,…
## $ CUBE_PH     <dbl> 106.74, 39.22, 84.55, 41.60, 57.18, 61.85, 52.99, 53.72, 7…
## $ CARTONS_PH  <dbl> 113.65, 37.18, 87.10, 115.07, 103.11, 144.80, 205.36, 58.1…
## $ PALLET_PH   <dbl> 5.62, 1.28, 3.23, 0.68, 1.89, 3.68, 1.79, 2.62, 6.05, 3.50…
## $ LINES_PH    <dbl> 4.62, 0.51, 1.61, 0.14, 0.61, 1.84, 1.79, 1.69, 4.84, 0.76…
## $ ACTUAL_TIME <dbl> 4.98, 3.90, 0.62, 7.30, 18.02, 10.87, 1.12, 6.50, 2.48, 13…

4.3.2.2 Offshore XGBoost Model

4.3.2.3 Offshore Linear Model

## ══ Workflow [trained] ══════════════════════════════════════════════════════════
## Preprocessor: Recipe
## Model: linear_reg()
## 
## ── Preprocessor ────────────────────────────────────────────────────────────────
## 0 Recipe Steps
## 
## ── Model ───────────────────────────────────────────────────────────────────────
## 
## Call:
## stats::lm(formula = ..y ~ ., data = data)
## 
## Coefficients:
## (Intercept)     STD_TIME   ONSTD_TIME         CUBE      CARTONS       PALLET  
##   4.202e-03    3.436e-03    1.156e+00    2.684e-05    1.426e-06   -1.020e-03  
##       LINES      CUBE_PH   CARTONS_PH    PALLET_PH     LINES_PH  
##   5.952e-04   -2.526e-06    1.248e-06   -1.416e-03   -1.009e-04

5 Model Accuracy

5.1 Domestic XGBOOST Model

5.2 Domestic Linear Model

5.3 Offshore XGBOOST Model

5.4 Offshore Linear Model

6 Conclusion

Both Linear Models have very high prediction accuracy of 99% for Offshore and Domestic SKUs respectively. Receiving Operations can apply these models to determine staffing requirements for offshore and domestic skus/trailers on a shift by shift basis.

7 Next Steps

  1. Develop Receiving WAB Tool for offshore and domestic trailers respectively.
  2. As part of deployment of the Receiving WAB Tool, there needs to be a report created that captures/reflects all the lagging indicators by shift. This report would be leveraged to extract the inputs into the Receiving WAB Tool for planning staff requirements and compare plan vs actual.